<?php


namespace Chenzeming\QiniuSecurity;


use Qiniu\Auth;
use Qiniu\Http\Client;

class QiniuSecurity
{
    public function index()
    {
        echo "这是一个测试文件";
    }


    static $err = '';

    private static $hook_url = '';

    //参数apiHost
    private const apiHost = 'ai.qiniuapi.com';
    //图片检测api地址
    private const imageCheckUrl = 'http://ai.qiniuapi.com/v3/image/censor';
    //图片检测项目配置 检测暴力和色情 敏感人物
    private const imageCheckScenes = ['pulp', 'terror', 'politician'];

    private const textCheckUrl = 'http://ai.qiniuapi.com/v3/text/censor';
    //文本检测项目 只有一个
    private const textCheckScenes = ['antispam'];

    private const videoCheckUrl = 'http://ai.qiniuapi.com/v3/video/censor';
    //    检测暴力和色情 敏感人物
    private const videoCheckScenes = ['pulp', 'terror', 'politician'];

    private static $access_key = '';
    private static $secret_key = '';

    private static function init()
    {
        $accessKey = self::$access_key;
        $secretKey = self::$secret_key;
        return new Auth($accessKey, $secretKey);
    }

    /**
     * 初始化账号
     * @param $access_key string 七牛云access_key
     * @param $secret_key string 七牛云secret_key
     * @return bool
     */
    public static function initAccount($access_key, $secret_key)
    {
        try {
            if (empty($access_key)) {
                self::$err = '缺少access_key';
            }
            if (empty($secret_key)) {
                self::$err = '缺少secret_key';
            }
            self::$access_key = $access_key;
            self::$secret_key = $secret_key;
            return true;
        } catch (\Exception $e) {
            return false;
        }

    }


    /**
     * 检测图片
     * @param string $imageUrl
     * @return bool
     */
    public static function checkImage($imageUrl = '')
    {
        try {
            if (empty($imageUrl)) {
                throw new \Exception('缺少待检测图片地址');
            }
            $body = [
                'data' => ['uri' => $imageUrl],
                'params' => ['scenes' => self::imageCheckScenes]//图片审核类型
            ];
            return self::apiPost($body, 'image');
        } catch (\Exception $e) {
            self::$err = $e->getMessage();
            return false;
        }
    }

    /**
     * 文本检测
     * @param string $text
     * @return bool
     */
    public static function checkText($text = '')
    {
        try {
            if (empty($text)) {
                throw new \Exception('缺少待检测文本');
            }
            $body = [
                'data' => ['text' => $text],
                'params' => ['scenes' => self::textCheckScenes]//图片审核类型
            ];
            return self::apiPost($body, 'text');
        } catch (\Exception $e) {
            self::$err = $e->getMessage();
            return false;
        }
    }

    /**
     * 视频检测接口
     * @param string $videoUrl
     * @param string $sn
     * @return bool
     */
    public static function checkVideo($videoUrl = '', $sn = '')
    {
        try {
            if (empty($videoUrl)) {
                throw new \Exception('视频链接地址');
            }
            if (empty(self::$hook_url)) {
                throw new \Exception('缺少回调地址，请调用setNotifyUrl方法设置');
            }
            if (empty($sn)) {
                $sn = self::makeRandSn();
            }
            $body = [
                'data' => ['uri' => $videoUrl, 'id' => $sn],
                'params' => ['scenes' => self::videoCheckScenes, 'hook_url' => self::$hook_url]//图片审核类型
            ];
            return self::apiPost($body, 'video');
        } catch (\Exception $e) {
            self::$err = $e->getMessage();
            return false;
        }
    }


    /**
     * 读取回调返回信息获取到需要得信息
     * @param array $result
     * @return array
     * "job" => "63536828a2cfbcaec1aa7e81"
     * "status" => false
     * "err" => "视频内容中包含 暴恐 信息"
     */
    public static function videoNotifyHandle($result = [])
    {
        try {
            if (empty($result)) {
                throw new \Exception('缺少结果信息');
            }
            $ret = [];
            $ret['job'] = $result['id'];
            $ret['status'] = false;
            $ret['err'] = '';

            //判断是否通过
            if ($result['result']['result']['suggestion'] == 'pass') {
                $ret['status'] = true;
                $ret['err'] = '';
            } else {
                $err = '';
                foreach ($result['result']['result']['scenes'] as $scene => $value) {
                    if ($value['suggestion'] != 'pass') {
                        foreach ($value['cuts'] as $cuts) {
                            if ($cuts['suggestion'] != 'pass') {
                                foreach ($cuts['details'] as $details) {
                                    if ($details['suggestion'] != 'pass') {
                                        $err = self::getScenesErrStr($scene, $details['label']);
                                        break 3;
                                    }

                                }
                            }
                        }
                    }
                }
                $ret['status'] = false;
                $ret['err'] = "视频内容中包含 " . $err . " 信息";
            }

            return $ret;
        } catch (\Exception $e) {
            $ret = [];
            $ret['job'] = $result['id'];
            $ret['status'] = false;
            $ret['err'] = $e->getMessage();
            return $ret;
        }
    }

    /**
     * 设置回调地址
     * @param string $url
     */
    public static function setNotifyUrl($url = '')
    {
        if (!empty($url)) {
            self::$hook_url = $url;
        }
    }


    /**
     * 公共发送
     * @param array $body
     * @param string $type
     * @return bool
     */
    private static function apiPost($body = [], $type = '')
    {
        try {
            $contentType = 'application/json';
            $method = 'POST';

            $auth = self::init();
            $api = '';
            switch ($type) {
                case 'image':
                    $api = self::imageCheckUrl;
                    break;
                case 'text':
                    $api = self::textCheckUrl;
                    break;
                case 'video':
                    $api = self::videoCheckUrl;
                    break;
            }
            if (empty($api)) {
                throw new \Exception('未知检测类型');
            }
            $headers = $auth->authorizationV2($api, $method, json_encode($body), $contentType);
            $headers['Content-Type'] = $contentType;
            $headers['Host'] = self::apiHost;
            $res = Client::post($api, json_encode($body), $headers);//需要引入命名空间
            $res = $res->body;
            $res = json_decode($res, true);
            //视频单独处理 视频只返回一个 jobId
            if ($type == 'video') {
                if (!isset($res['job'])) {
                    throw new \Exception('请求失败');
                } else {
                    return $res['job'];
                }
            }

            if ($res['code'] != 200) {
                throw new \Exception($res['message']);
            }
            switch ($type) {
                case 'image':
                    return self::imageCheckHandle($res);
                case 'text':
                    return self::textCheckHandle($res);
                default:
                    throw new \Exception('未知检测类型');
            }

        } catch (\Exception $e) {
            self::$err = $e->getMessage();
            return false;
        }

    }


    /**
     * 文本检测回复处理
     * @param array $res
     * @return bool
     */
    private static function textCheckHandle($res = [])
    {
        try {
            if ($res['result']['suggestion'] == 'pass') {
                return true;
            } else {
                //如果有识别未通过抛出错误
                $errStr = '';
                foreach ($res['result']['scenes'] as $scenes => $value) {
                    //继续循环
                    if ($value['suggestion'] != 'pass') {
                        foreach ($value['details'] as $details) {
                            $errStr = self::getScenesErrStr($scenes, $details['label']);
                            break 2;
                        }
                    }
                }
                $errStr = '内容包含' . $errStr . '信息';
                throw new \Exception($errStr);
            }
        } catch (\Exception $e) {
            self::$err = $e->getMessage();
            return false;
        }
    }


    /**
     * 图片检测公共返回
     * @param array $res
     * @return bool
     */
    private static function imageCheckHandle($res = [])
    {
        try {
            //鉴定结果通过 ，无色请
            if ($res['result']['suggestion'] == 'pass') {
                return true;
            } else {
                //如果有识别未通过抛出错误
                $errStr = '';
                foreach ($res['result']['scenes'] as $scenes => $value) {
                    //继续循环
                    if ($value['suggestion'] != 'pass') {
                        foreach ($value['details'] as $details) {
                            if ($details['suggestion'] != 'pass') {
                                if ($scenes == 'politician') {
                                    //这里识别政要人像 是直接返回 人名的
                                    $errStr = $details['label'];
//                                    $errStr = self::getScenesErrStr($scenes,$details['group']);
                                } else {
                                    $errStr = self::getScenesErrStr($scenes, $details['label']);
                                }
                                break 2;
                            }
                        }
                    }
                }
                $errStr = '内容包含' . $errStr . '信息';
                throw new \Exception($errStr);
            }
        } catch (\Exception $e) {
            self::$err = $e->getMessage();
            return false;
        }
    }

    private static function makeRandSn()
    {
        return date('YmdHis') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
    }


    private static function getScenesErrStr($scenes, $label)
    {
        $arr = [
            'pulp' => [
                'normal' => '正常图片，无色情内容',
                'sexy' => '性感图片',
                'pulp' => '色情图片',
            ],
            'terror' => [
                'bloodiness' => '血腥',
                'self_burning' => '自焚',
                'beheaded' => '斩首类',
                'march_crowed' => '人群聚集类',
                'fight_police' => '警民冲突',
                'fight_person' => '民众肢体接触',
                'illegal_flag' => '违规旗帜类',
                'guns' => '枪',
                'knives' => '刀',
                'anime_bloodiness' => '动漫血腥类',
                'anime_knives' => '二次元刀',
                'anime_guns' => '二次元枪',
                'politics' => '涉政',
                'violence' => '暴恐',
                'normal' => '正常',
            ],
            'politician' => [
                'domestic_statesman' => '国内政要',
                'foreign_statesman' => '国外政要',
                'chinese_martyr' => '革命英烈',
                'affairs_official_gov' => '落马官员（政府）',
                'affairs_official_ent' => '落马官员（企事业）',
                'terrorist' => '恐怖分子',
                'affairs_celebrity' => '劣迹艺人',
                'politics' => '涉政人物',
            ],
            //为本的对应
            'antispam' => [
                'normal' => '正常文本',
                'spam' => '含垃圾信息',
                'ad' => '广告',
                'politics' => '涉政',
                'terrorism' => '暴恐',
                'abuse' => '辱骂',
                'porn' => '色情',
                'flood' => '灌水',
                'contraband' => '违禁',
                'meaningless' => '无意义',
            ]
        ];
        if (!isset($arr[$scenes][$label])) {
            return '未知识别错误';
        }
        return $arr[$scenes][$label];
    }

}